#include <osal/osal.h>
#include <basic_types.h>
#include <hld/hld_dev.h>
#include <hld/dmx/dmx_dev.h>
#include <hld/dmx/dmx.h>
#include <api/libc/alloc.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <api/libtsi/si_types.h>
//#include <api/libtsi/si_table.h>

#include <api/libsubt/lib_subt.h>
#include <api/libsubt/subt_osd.h>
#include <hld/sdec/sdec.h>
#ifdef LIB_TSI3_FULL
#include <api/libtsi/si_section.h>
#include <api/libsi/desc_loop_parser.h>
#include <api/libsi/sie_monitor.h>
#endif
#include <api/libsi/psi_pmt.h>

#ifndef SEE_CPU

struct t_subt_lang g_subt_lang[SUBTITLE_LANG_NUM];
UINT8 g_subt_lang_num =0;
UINT8 g_current_lang = 0xff;
UINT16 g_current_pid =0x1fff;

#ifdef PVR_DYNAMIC_PID_MONITOR_SUPPORT

UINT8 rec_monitor_id_subt_lang_num[2][2];
struct t_subt_lang rec_monitor_id_subt_lang[2][2][SUBTITLE_LANG_NUM];
#endif

BOOL g_subt_enable = FALSE;
BOOL g_dcii_subt_enable = FALSE;            // ZJX
BOOL g_pvrsubt_enable = FALSE;
static UINT16 dmx_index = 0;

static SUBT_EVENT_CALLBACK subt_event_callback = NULL;
#ifdef ATSC_SUBTITLE_SUPPORT
static SUBT_TYPE g_subt_type[SUBTITLE_LANG_NUM]; 
SUBT_TYPE g_current_subt_type = DVB_SUBT;
static BOOL g_is_atsc_subt =FALSE;		//no use, now
#endif

#ifdef LIB_TSI3_FULL

static UINT8 prev_subt[256];

static INT32 iso639_desc_handle(UINT8 tag, UINT8 len, UINT8 *desc, void *priv)
{
	UINT8 i = 0, j = 0;
	UINT8 k = 0;
    int index = 0;
	struct pmt_es_info *es = (struct pmt_es_info *)priv;
	//es->lang size is only 3 byte, but some abnomal component audio has more than 1 language
	for( i = 0; i < len; i += 4)
	{
        if((k+3) < 64)
        {
		    //MEMCPY(&es->lang[k], (desc + i), 3);
		    for (j=i; j<i+3; j++) 
			{
                if ( (*(desc+j) >= 'a' && *(desc+j) <= 'z')||(*(desc+j) >= 'A' && *(desc+j) <= 'Z'))
                    es->lang[index++] = *(desc+j);
                else
                    es->lang[index++] = 'a';
		    }
		    k += 3;
        }
        else
        {
            break;
        }
	}
	return SI_SUCCESS;
}


struct desc_table subt_desc_info[] = {
	{
		SUBTITLE_DESCRIPTOR,
		0,
		(desc_parser_t)subt_descriptor,
	},
};
struct desc_table atsc_subt_desc_info[] = {
	{
		ISO_639_LANGUAGE_DESCRIPTOR, 
		0,
		(desc_parser_t)iso639_desc_handle,
	},
};




#ifdef ATSC_SUBTITLE_SUPPORT

void subt_one_lang(UINT32 pid, UINT8 *lang)     // Register new language
{
    UINT32 i = 0;
//    if(!g_subt_registered)
//        return;
    g_is_atsc_subt = TRUE;
    for(i = 0 ; i < g_subt_lang_num ; ++i)
    {
        if( g_subt_lang[i].pid == pid)          // Current language was included in subtitle aready registed. 
            return;
    }
    
	if(g_subt_lang_num +1 <= SUBTITLE_LANG_NUM)
	{
        g_subt_lang[g_subt_lang_num].pid = pid; // Different language corresponded with different pid
        g_subt_type[g_subt_lang_num] = ATSC_SUBT;
        for(i = 0 ; i < 3 ; ++i)
        {
            g_subt_lang[g_subt_lang_num].lang[i]= lang[i];
        }
        g_subt_lang_num ++;
	}
}

INT32 atsc_subt_callback(UINT8 *buff, INT32 len, UINT32 param)
{
	INT32 prog_info_length;
	INT32 es_info_length;
	INT32 i;
	UINT16 es_pid;
	struct pmt_es_info es;
	UINT8* buf0;
	buf0 = buff+12+(((buff[10]<<8)|buff[11])&0x0FFF);
	struct pmt_section *pms = (struct pmt_section *)buf0;
	struct pmt_stream_info *stream;

	prog_info_length = SI_MERGE_HL8(pms->program_info_length);
	for(i=0; i<len-4; i+=es_info_length+sizeof(struct pmt_stream_info)) 
	{   
		
		stream = (struct pmt_stream_info *)(buf0+i);
		MEMSET(&es, 0, sizeof(struct pmt_es_info));
		es.stream_type = stream->stream_type;
		if(es.stream_type == ATSC_SUBT_STREAM)
		{
			es.pid = SI_MERGE_HL8(stream->elementary_pid);
			desc_loop_parser(stream->descriptor, es_info_length, atsc_subt_desc_info, 1, NULL, (void *)&es);
			subt_one_lang(es.pid,es.lang);
		}
		es_info_length = SI_MERGE_HL8(stream->es_info_length);
	}
	return SUCCESS;
}

#ifdef DUAL_ENABLE
INT32 atsc_sdec_m3327_request_write(void* pdev,UINT32 uSizeRequested,UINT8** ppuData,UINT32* puSizeGot)
{
 
}
void atsc_sdec_m3327_update_write(void* pdev,UINT32 uSize)
{
	
}

static UINT8 atsc_subt_dmx_used[3] = {0,0,0};
static RET_CODE atsc_subt_unreg_all_dmx()
{
	static struct dmx_device *dmx_dev;
	RET_CODE reg_code = RET_SUCCESS;
	UINT8 i = 0;
	for(i=0; i<3; i++)
	{
		if(atsc_subt_dmx_used[i])
		{
			dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, i); 
			reg_code = dmx_unregister_service(dmx_dev,6);
			if(reg_code != RET_SUCCESS)
			{
				LIBSUBT_PRINTF("%s : Error: subt fail to stop dmx[%d]!\n",__FUNCTION__,i);
				return !RET_SUCCESS;
			}
			else
			{
				LIBSUBT_PRINTF("%s : subt success to stop dmx[%d]!\n",__FUNCTION__,i);
			}
			atsc_subt_dmx_used[i]=0;
		}
	}
}
#endif


#endif
static BOOL g_is_subt_available = FALSE;

BOOL subt_is_available()
{
	return g_is_subt_available;
}



INT32 subt_callback(UINT8 *buff, INT32 len, UINT32 param)
{
	INT32 prog_info_length;
	INT32 es_info_length;
	INT32 i;
	UINT16 es_pid;
	
	struct pmt_section *pms = (struct pmt_section *)buff;
	struct pmt_stream_info *stream;

	prog_info_length = SI_MERGE_HL8(pms->program_info_length);

	g_is_subt_available = FALSE;
	
	for(i=sizeof(struct pmt_section)+prog_info_length-4; i<len-4; i+=es_info_length+sizeof(struct pmt_stream_info)) 
	{
		stream = (struct pmt_stream_info *)(buff+i);
		es_info_length = SI_MERGE_HL8(stream->es_info_length);
		es_pid = SI_MERGE_HL8(stream->elementary_pid);
		desc_loop_parser(stream->descriptor, es_info_length, subt_desc_info, 1, NULL, (void *)&es_pid);
		#ifdef ATSC_SUBTITLE_SUPPORT
		if (stream->stream_type == ATSC_SUBT_STREAM)
			g_is_subt_available = TRUE;
		#endif
	}
	return SUCCESS;
}

INT32 subt_unregister(UINT32 monitor_id)
{
	UINT16 stuff_pid = 0x1FFF;
	struct sim_cb_param param;
	if( sim_get_monitor_param(monitor_id, &param) == SUCCESS)
	{
		if(
			#ifdef ATSC_SUBTITLE_SUPPORT
			sim_unregister_scb(monitor_id, atsc_subt_callback)!= SUCCESS&&
			#endif
			sim_unregister_scb(monitor_id, subt_callback)!= SUCCESS)
		{
			LIBSUBT_PRINTF("%s : Error: subt fail to unmount to monitor[%d]!\n",__FUNCTION__,monitor_id);
			return ERR_FAILUE;
		}
	}
	
	LIBSUBT_PRINTF("%s : subt success to unmount to monitor[%d]!\n",__FUNCTION__,monitor_id);
	subt_descriptor(SUBTITLE_DESCRIPTOR, 0, prev_subt, (void *)&stuff_pid);
	return SUCCESS;
}

static UINT8 subt_cur_monitor_id = 0xff;
INT32 subt_register(UINT32 monitor_id)
{
	struct sim_cb_param param;
	if( sim_get_monitor_param(monitor_id, &param) != SUCCESS)
	{
		LIBSUBT_PRINTF("%s : Error1: subt fail to mount to monitor[%d]!\n",__FUNCTION__,monitor_id);
		return ERR_FAILUE;
	}
//modify for:we shuld get the dmx_index  before unregister one dmx  20111226
	if(
        #ifdef ATSC_SUBTITLE_SUPPORT
		sim_register_scb(monitor_id, atsc_subt_callback, NULL)==SUCCESS&&
		#endif
		sim_register_scb(monitor_id, subt_callback, NULL)==SUCCESS)
		dmx_index = param.dmx_idx;
//modify end		
	subt_unregister(subt_cur_monitor_id);
	
	if(
		#ifdef ATSC_SUBTITLE_SUPPORT
		sim_register_scb(monitor_id, atsc_subt_callback, NULL)==SUCCESS&&
		#endif
		sim_register_scb(monitor_id, subt_callback, NULL)==SUCCESS)
	{
		dmx_index = param.dmx_idx;
		subt_cur_monitor_id = monitor_id;
		LIBSUBT_PRINTF("%s : subt success to mount to monitor[%d]!\n",__FUNCTION__,monitor_id);
		return SUCCESS;
	}
	LIBSUBT_PRINTF("%s : Error2: subt fail to mount to monitor[%d]!\n",__FUNCTION__,monitor_id);	
	return ERR_FAILUE;	
}


#endif

static UINT8 subt_dmx_used[3] = {0,0,0};
static RET_CODE subt_unreg_all_dmx()
{
	static struct dmx_device *dmx_dev;
	RET_CODE reg_code = RET_SUCCESS;
	UINT8 i = 0;
	for(i=0; i<3; i++)
	{
		if(subt_dmx_used[i])
		{
			dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, i); 
			reg_code = dmx_unregister_service(dmx_dev,4);
			if(reg_code != RET_SUCCESS)
			{
				LIBSUBT_PRINTF("%s : Error: subt fail to stop dmx[%d]!\n",__FUNCTION__,i);
				return !RET_SUCCESS;
			}
			else
			{
				LIBSUBT_PRINTF("%s : subt success to stop dmx[%d]!\n",__FUNCTION__,i);
			}
			subt_dmx_used[i]=0;
		}
	}
}


INT32 subt_restart(UINT16 pid)
{
    UINT8 lang_idx,lang=0;
    UINT16 page_num = 0xffff;
    struct register_service subt_Serv;
    static struct dmx_device *dmx_dev;
    static struct sdec_device *sdec_dev;
	RET_CODE reg_code = RET_SUCCESS;
	LIBSUBT_PRINTF("%s : subt[%d] PID[%d] changed!\n",__FUNCTION__,g_subt_enable,pid);
    sdec_dev = (struct sdec_device *)dev_get_by_name("SDEC_M3327_0");
    //dmx_dev = (struct dmx_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_DMX);
    dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, dmx_index);
//    libc_printf("%s: g_subt_lang_num=%d, g_subt_enable=%d\n", __FUNCTION__, g_subt_lang_num, g_subt_enable);
 
    if(g_subt_enable == TRUE)
    {
    	LIBSUBT_PRINTF("%s-sdec_stop()\n",__FUNCTION__);	
        sdec_stop(sdec_dev);
    }
#ifdef ATSC_SUBTITLE_SUPPORT	
    if(pid != g_current_pid && g_current_subt_type!= ATSC_SUBT)
#else
	if(pid != g_current_pid)
#endif	
    {
        g_current_pid = pid;
        if(g_subt_enable == TRUE)
        {
            subt_unreg_all_dmx();
            subt_Serv.device = sdec_dev;
            subt_Serv.request_write = (Request_write)sdec_request_write;
            subt_Serv.update_write = (Update_write)sdec_update_write;
            subt_Serv.service_pid = g_current_pid;
            reg_code = dmx_register_service(dmx_dev,4,&subt_Serv);
		if(reg_code == RET_SUCCESS)
		{
			subt_dmx_used[dmx_index] = 1;
			LIBSUBT_PRINTF("%s : subt success to start dmx[%d]!\n",__FUNCTION__,dmx_index);
		}
		else
		{
			LIBSUBT_PRINTF("%s : Error: subt fail to start dmx[%d]!\n",__FUNCTION__,dmx_index);
		}
        }
    }

    for(lang_idx = 0;lang_idx<g_subt_lang_num;lang_idx++)
    {
        if(g_subt_lang[lang_idx].pid == pid)
            lang = lang_idx;
    }
    
    if(g_subt_enable == TRUE)
    {
//        libc_printf("lang=%d\n",lang);
	LIBSUBT_PRINTF("%s-sdec_start()\n",__FUNCTION__);
        sdec_start(sdec_dev,g_subt_lang[lang].com_page,g_subt_lang[lang].anci_page);
    }
    return SUCCESS;
}
//////////////////////////////////////////////////////////////////////////
//add for DVBC
static UINT8 default_subt_lang= 0xFF;
void set_default_subt_lang(UINT8 lang)
{
	default_subt_lang = lang;
	LIBSUBT_PRINTF("%s : user set %dth as default subt!\n",__FUNCTION__,lang);
}
//////////////////////////////////////////////////////////////////////////
UINT32 g_subt_desc_get = 0;
INT32 subt_descriptor(UINT8 tag, INT32 desc_length, UINT8 *desc, void *param)
{
	UINT8 lang_idx;
	struct register_service subt_Serv;
	RET_CODE reg_code = RET_SUCCESS;
	UINT16 pid = *((UINT16*)param);
	static struct dmx_device *dmx_dev;
	static struct sdec_device *sdec_dev;

	g_is_subt_available = TRUE;
	
	if(g_pvrsubt_enable == TRUE)//pvr
		return SI_SUCCESS;
#ifdef LIB_TSI3_FULL
	if(pid!=0x1FFF && MEMCMP(desc, prev_subt, desc_length) == 0)
		return SI_SUCCESS;
	MEMSET(prev_subt, 0, sizeof(prev_subt));
	MEMCPY(prev_subt, desc, desc_length);
#endif

	LIBSUBT_PRINTF("%s : pid[%d], length[%d]!\n",__FUNCTION__,pid,desc_length);

	sdec_dev = (struct sdec_device *)dev_get_by_name("SDEC_M3327_0");
	//dmx_dev = (struct dmx_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_DMX);
	dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, dmx_index);
	if(pid <0x20 || pid == 0x1fff )		
	{
		g_is_subt_available = FALSE;
		g_current_pid = 0x1fff;
		g_subt_lang_num = 0;
		g_current_lang = 0xff;
		if(g_subt_enable == TRUE ||g_dcii_subt_enable == TRUE )
		{
		#ifdef ATSC_SUBTITLE_SUPPORT
            #ifdef DUAL_ENABLE
            atsc_subt_unreg_all_dmx();		
	        LIBSUBT_PRINTF("%s-lib_subt_atsc_terminate_task()\n",__FUNCTION__);			            
            lib_subt_atsc_terminate_task();             // new added   The purpose of adding this two line code is to stop atsc_task();  
			lib_subt_atsc_section_parse_terminate_task();
			g_current_subt_type=DVB_SUBT;
			#endif

			#ifndef DUAL_ENABLE
            lib_subt_atsc_stop_filter(dmx_index);			// new added
	        LIBSUBT_PRINTF("%s-lib_subt_atsc_terminate_task()\n",__FUNCTION__);			            
            lib_subt_atsc_terminate_task();             // new added   The purpose of adding this two line code is to stop atsc_task();  
			g_current_subt_type=DVB_SUBT;
			#endif
		
		#endif
		    LIBSUBT_PRINTF("%s-sdec_stop()\n",__FUNCTION__);	
			sdec_stop(sdec_dev);			
			subt_unreg_all_dmx();
	//		if(reg_code == RET_SUCCESS)
	//			libc_printf("subt_descriptor unreg %d\n",dmx_index);
	//		else
	//			libc_printf("\nfail to unreg %d\n", dmx_index);
		}
		g_subt_desc_get = 0;
		return SI_SUCCESS;	
	}
	if(desc_length<8)
	{
		if(g_subt_lang_num>=SUBTITLE_LANG_NUM)
			return SI_SUCCESS;	
		for(lang_idx = 0;lang_idx<g_subt_lang_num;lang_idx++)
		{
			if((desc[0] == g_subt_lang[lang_idx].lang[0]) 
				&&(desc[1] == g_subt_lang[lang_idx].lang[1]) 
				&&(desc[2] == g_subt_lang[lang_idx].lang[2])
				&&(desc[3] == g_subt_lang[lang_idx].subt_type)
				&&((desc[4]<<8) + desc[5] == g_subt_lang[lang_idx].com_page)
				&&((desc[6]<<8) + desc[7] == g_subt_lang[lang_idx].anci_page)
				&&(pid == g_subt_lang[lang_idx].pid))
				break;
		}		
		if(lang_idx>=g_subt_lang_num)//not same with anyone of the old
		{		
			g_subt_lang[g_subt_lang_num].lang[0]='x';
			g_subt_lang[g_subt_lang_num].lang[1]='x';
			g_subt_lang[g_subt_lang_num].lang[2]='x';			
			g_subt_lang[g_subt_lang_num].pid = pid;
			g_subt_lang[g_subt_lang_num].subt_type = 0x10;
			g_subt_lang[g_subt_lang_num].com_page = 0;
			g_subt_lang[g_subt_lang_num].anci_page = 0;		
			#ifdef ATSC_SUBTITLE_SUPPORT
		       g_subt_type[g_subt_lang_num] = DVB_SUBT;			
			#endif
			g_subt_lang_num ++;	
		}
	}
	while(desc_length>=8)
	{
		if(g_subt_lang_num>=SUBTITLE_LANG_NUM)
		{
			g_subt_desc_get = 1;
			return SI_SUCCESS;	
		}
		
		for(lang_idx = 0;lang_idx<g_subt_lang_num;lang_idx++)
		{
			if((desc[0] == g_subt_lang[lang_idx].lang[0]) 
				&&(desc[1] == g_subt_lang[lang_idx].lang[1]) 
				&&(desc[2] == g_subt_lang[lang_idx].lang[2])
				&&(desc[3] == g_subt_lang[lang_idx].subt_type)
				&&((desc[4]<<8) + desc[5] == g_subt_lang[lang_idx].com_page)
				&&((desc[6]<<8) + desc[7] == g_subt_lang[lang_idx].anci_page)
				&&(pid == g_subt_lang[lang_idx].pid))
				break;
		}
		if(lang_idx>=g_subt_lang_num)//not same with anyone of the old
		{		
			//if((desc[3]>=0x10 && desc[3]<=0x13)||(desc[3]>=0x20 && desc[3]<=0x23))
			{//en300468 table26
				g_subt_lang[g_subt_lang_num].lang[0]=desc[0];
				g_subt_lang[g_subt_lang_num].lang[1]=desc[1];
				g_subt_lang[g_subt_lang_num].lang[2]=desc[2];

				g_subt_lang[g_subt_lang_num].pid = pid;
				g_subt_lang[g_subt_lang_num].subt_type = desc[3];
				g_subt_lang[g_subt_lang_num].com_page = (desc[4]<<8) + desc[5];
				g_subt_lang[g_subt_lang_num].anci_page = (desc[6]<<8) + desc[7];
				#ifdef ATSC_SUBTITLE_SUPPORT
			       g_subt_type[g_subt_lang_num] = DVB_SUBT;			
				#endif
				g_subt_lang_num++;
			}
		}
		
		desc += 8;
		desc_length -= 8;
		
	}
#ifndef DUAL_ENABLE
    //For S3602f, we dont recommend using such function, if app can fix below issue by other way, 
    //it would be better. Need to check this with Cloud later if we can remove below code or not.
    //--Michael 2009/07/27
    if(get_sdec_status()== TRUE)
    {//cloud, restart sdec to avoid stopping sdec in dynamic pid case
      //  subt_restart(pid);
    }
#endif
    if( default_subt_lang!= 0xFF)
        subt_set_language(default_subt_lang);

	g_subt_desc_get = 1;
    return SI_SUCCESS;
		
}
#ifdef PVR_DYNAMIC_PID_MONITOR_SUPPORT
INT32 rec_subt_descriptor(UINT16 dmx_id,UINT8 prog_index,UINT8 tag, INT32 desc_length, UINT8 *desc, void *param)
{
	UINT8 lang_idx;
	struct register_service subt_Serv;
	struct sim_cb_param *sim_param;
	UINT16 pid = *((UINT16*)param);
	LIBSUBT_PRINTF("pid = %d \n",pid );
	static struct dmx_device *dmx_dev;
	static struct sdec_device *sdec_dev;
	//if(g_pvrsubt_enable == TRUE)//pvr
		//return SI_SUCCESS;
	dmx_dev=(struct nim_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, (dmx_id));
	rec_monitor_id_subt_lang_num[dmx_id][prog_index] = 0;
	if(pid <0x20 || pid == 0x1fff)		
	{
		//g_current_pid = 0x1fff;
		rec_monitor_id_subt_lang_num[dmx_id][prog_index] = 0;
		//g_current_lang = 0xff;
#if 0		
		if(g_subt_enable == TRUE)
		{
			sdec_stop(sdec_dev);
			dmx_unregister_service(dmx_dev,4);		
		}
#endif		
		return SI_SUCCESS;	
	}
	if(desc_length<8)
	{
		if(rec_monitor_id_subt_lang_num[dmx_id][prog_index]>=SUBTITLE_LANG_NUM)
			return SI_SUCCESS;	
		for(lang_idx = 0;lang_idx<rec_monitor_id_subt_lang_num[dmx_id][prog_index];lang_idx++)
		{
			if((desc[0] == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].lang[0]) 
				&&(desc[1] == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].lang[1]) 
				&&(desc[2] == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].lang[2])
				&&(desc[3] == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].subt_type)
				&&((desc[4]<<8) + desc[5] == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].com_page)
				&&((desc[6]<<8) + desc[7] == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].anci_page)
				&&(pid == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].pid))
				break;
		}		
		if(lang_idx>=rec_monitor_id_subt_lang_num[dmx_id][prog_index])//not same with anyone of the old
		{		
			rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].lang[0]='x';
			rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].lang[1]='x';
			rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].lang[2]='x';
			rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].pid = pid;
			rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].subt_type = 0x10;
			rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].com_page = 0;
			rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].anci_page = 0;		
			rec_monitor_id_subt_lang_num[dmx_id][prog_index] ++;	
		}
	}
	while(desc_length>=8)
	{
		if(rec_monitor_id_subt_lang_num[dmx_id][prog_index]>=SUBTITLE_LANG_NUM)
			return SI_SUCCESS;	
		for(lang_idx = 0;lang_idx<rec_monitor_id_subt_lang_num[dmx_id][prog_index];lang_idx++)
		{
			if((desc[0] == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].lang[0]) 
				&&(desc[1] == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].lang[1]) 
				&&(desc[2] == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].lang[2])
				&&(desc[3] == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].subt_type)
				&&((desc[4]<<8) + desc[5] == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].com_page)
				&&((desc[6]<<8) + desc[7] == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].anci_page)
				&&(pid == rec_monitor_id_subt_lang[dmx_id][prog_index][lang_idx].pid))
				break;
		}
		if(lang_idx>=rec_monitor_id_subt_lang_num[dmx_id][prog_index])//not same with anyone of the old
		{		
			//if((desc[3]>=0x10 && desc[3]<=0x13)||(desc[3]>=0x20 && desc[3]<=0x23))
			{//en300468 table26
				rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].lang[0]=desc[0];
				rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].lang[1]=desc[1];
				rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].lang[2]=desc[2];
				rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].pid = pid;
				rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].subt_type = desc[3];
				rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].com_page = (desc[4]<<8) + desc[5];
				rec_monitor_id_subt_lang[dmx_id][prog_index][rec_monitor_id_subt_lang_num[dmx_id][prog_index]].anci_page = (desc[6]<<8) + desc[7];
				rec_monitor_id_subt_lang_num[dmx_id][prog_index]++;
			}
		}
		desc += 8;
		desc_length -= 8;
	}
    return SI_SUCCESS;
}

#endif
UINT32 subt_get_language(struct t_subt_lang** list ,UINT8* num)
{
	*num = g_subt_lang_num;
	*list = g_subt_lang;
	return g_subt_desc_get;
}

#ifdef PVR_DYNAMIC_PID_MONITOR_SUPPORT
void Rec_Monitor_subt_get_language(UINT16 dmx_id,UINT8 prog_index,struct t_subt_lang** list ,UINT8* num)
{
	*num = rec_monitor_id_subt_lang_num[dmx_id][prog_index];
	*list = rec_monitor_id_subt_lang[dmx_id][prog_index];
}
#endif
UINT8 subt_get_cur_language(void)
{
	return g_current_lang;
}
INT32 subt_set_language(UINT8 lang)
{
	UINT8 lang_idx;
	UINT16 page_num = 0xffff;
	struct register_service subt_Serv;
	static struct sdec_device *sdec_dev = NULL;
	struct dmx_device *dmx_dev = NULL;
	RET_CODE reg_code = RET_SUCCESS;
	sdec_dev = (struct sdec_device *)dev_get_by_name("SDEC_M3327_0");
	dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, dmx_index);
	LIBSUBT_PRINTF("%s : index[%d], subt_enable[%d], pvr_enable[%d]!\n",__FUNCTION__,lang,g_subt_enable,g_pvrsubt_enable);
	if(lang>=g_subt_lang_num)
	{
		LIBSUBT_PRINTF("%s : Error: index out of range!\n",__FUNCTION__);
		return ERR_FAILUE;
	}
    
	if(g_subt_enable == TRUE||g_pvrsubt_enable == TRUE||g_dcii_subt_enable == TRUE)
	{
#ifdef ATSC_SUBTITLE_SUPPORT	
        #ifdef DUAL_ENABLE
        atsc_subt_unreg_all_dmx();
	    LIBSUBT_PRINTF("%s-lib_subt_atsc_terminate_task()\n",__FUNCTION__);			                    
        lib_subt_atsc_terminate_task();   //need remote call
        lib_subt_atsc_section_parse_terminate_task();
		#endif

		#ifndef DUAL_ENABLE
        lib_subt_atsc_stop_filter(dmx_index);		//Cpu code
	    LIBSUBT_PRINTF("%s-lib_subt_atsc_terminate_task()\n",__FUNCTION__);			                    
        lib_subt_atsc_terminate_task();   //need remote call
        #endif
	}
    LIBSUBT_PRINTF("g_subt_type[lang]=%d\n",g_subt_type[lang]);
    //if(g_is_atsc_subt)
    if(g_subt_type[lang] == ATSC_SUBT)                  // Current set language index will be processed by ATSC subtitle.
    {
        g_current_subt_type = ATSC_SUBT;
        if(g_subt_lang[lang].pid != g_current_pid)
        {
            g_current_pid = g_subt_lang[lang].pid;
        }

        if(g_current_pid != 0x1fff)
        {
			#ifdef DUAL_ENABLE
    	    LIBSUBT_PRINTF("%s-sdec_stop()\n",__FUNCTION__);				
            sdec_stop(sdec_dev);
            lib_subt_atsc_clean_up();		//need remote call
            lib_subt_atsc_delete_timer(); // need remote call		
			atsc_subt_unreg_all_dmx();
			subt_Serv.device = sdec_dev;
			subt_Serv.request_write = (Request_write)atsc_sdec_m3327_request_write;
			subt_Serv.update_write = (Update_write)atsc_sdec_m3327_update_write;
			subt_Serv.service_pid = g_current_pid;
			subt_Serv.str_type = DC2SUB_STR;
			reg_code = dmx_register_service(dmx_dev,6,&subt_Serv);
			if(reg_code == RET_SUCCESS)
			{
				atsc_subt_dmx_used[dmx_index] = 1;
				LIBSUBT_PRINTF("%s : subt success to start dmx[%d]!\n",__FUNCTION__,__LINE__,dmx_index);
			}
			else
			{
				LIBSUBT_PRINTF("%s :line %d: Error: subt fail to start dmx[%d]!\n",__FUNCTION__,__LINE__,dmx_index);
			}
			LIBSUBT_PRINTF("%s-lib_subt_atsc_create_task()\n",__FUNCTION__);
			lib_subt_atsc_section_parse_create_task();//need remote call
            lib_subt_atsc_create_task(); 	//need remote call
            return SUCCESS;
			#endif

			#ifndef DUAL_ENABLE
            subt_unreg_all_dmx();
    	    LIBSUBT_PRINTF("%s-sdec_stop()\n",__FUNCTION__);				
            sdec_stop(sdec_dev);
            lib_subt_atsc_clean_up();		//need remote call
            lib_subt_atsc_delete_timer(); // need remote call
            lib_subt_atsc_start_filter(dmx_index,g_current_pid);
			LIBSUBT_PRINTF("%s-lib_subt_atsc_create_task()\n",__FUNCTION__);						
            lib_subt_atsc_create_task(); 	//need remote call
            return SUCCESS;
			#endif
        }
        return SUCCESS;
#else
	 sdec_stop(sdec_dev);
#endif
    }

//	if(g_subt_enable == TRUE||g_pvrsubt_enable == TRUE)
//	{
//		sdec_stop(sdec_dev);
//	}
	if(g_subt_lang[lang].pid != g_current_pid)
	{
		if (subt_event_callback != NULL)
			subt_event_callback(SUBT_PID_UPDATE, g_subt_lang[lang].pid);
		g_current_pid = g_subt_lang[lang].pid;
#ifdef ATSC_SUBTITLE_SUPPORT
        g_current_subt_type = DVB_SUBT;
#endif
		if(g_subt_enable == TRUE || g_pvrsubt_enable == TRUE)
		{			
			subt_unreg_all_dmx();
			subt_Serv.device = sdec_dev;
			subt_Serv.request_write = (Request_write)sdec_request_write;
			subt_Serv.update_write = (Update_write)sdec_update_write;
			subt_Serv.service_pid = g_current_pid;
			reg_code = dmx_register_service(dmx_dev,4,&subt_Serv);
			if(reg_code == RET_SUCCESS)
			{
				subt_dmx_used[dmx_index] = 1;
				LIBSUBT_PRINTF("%s : subt success to start dmx[%d]!\n",__FUNCTION__,dmx_index);
			}
			else
			{
				LIBSUBT_PRINTF("%s : Error: subt fail to start dmx[%d]!\n",__FUNCTION__,dmx_index);
			}
		}
	}
	if(g_subt_enable == TRUE||g_pvrsubt_enable == TRUE)
	{
	LIBSUBT_PRINTF("%s-sdec_start()\n",__FUNCTION__);	
	    sdec_stop(sdec_dev);
		sdec_start(sdec_dev,g_subt_lang[lang].com_page,g_subt_lang[lang].anci_page);
	}
	g_current_lang = lang;

	return SUCCESS;
}

/*
subt_show_onoff is called when user graphic off/on,because subtitle can not overlap with user graphic,
so when user graphic show , subtitle off, user graphic not show , subtitle on.
*/
#ifdef _MHEG5_ENABLE_
extern void tmMHEG5Stop_2();
extern void tmMHEG5Start_2();
#endif

INT32 subt_show_onoff(BOOL bOn)
{ 
#ifdef ATSC_SUBTITLE_SUPPORT
    lib_subt_atsc_show_onoff(bOn);
#endif
	LIBSUBT_PRINTF("%s : On[%d]!\n",__FUNCTION__,bOn);
	if(bOn == TRUE)
	{
#ifdef _MHEG5_ENABLE_
		tmMHEG5Stop_2();
#endif
		osd_subt_enter();
	}
	else
	{
#ifdef _MHEG5_ENABLE_
		tmMHEG5Start_2();
#endif
		osd_subt_leave();
    }
}

/*
	subt_enable is for special use .
	Now, it's disabled when can not share mem DVW
*/
INT32 subt_enable(BOOL enable)
{
	struct register_service subt_Serv;
	static struct sdec_device *sdec_dev;
	struct dmx_device *dmx_dev = NULL;
	RET_CODE reg_code = RET_SUCCESS;

	sdec_dev = (struct sdec_device *)dev_get_by_name("SDEC_M3327_0");
	//subt_dmx_dev = (struct dmx_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_DMX);
	dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, dmx_index);
	LIBSUBT_PRINTF("%s : Enable[%d]!\n",__FUNCTION__,enable);
#ifdef ATSC_SUBTITLE_SUPPORT
    if(g_current_subt_type == ATSC_SUBT)
    {
        if(g_subt_lang_num>0 && g_current_pid != 0x1fff)
        {
            subt_unreg_all_dmx();
	    	LIBSUBT_PRINTF("%s-sdec_stop() -Line(%d)\n",__FUNCTION__,__LINE__);				
		    sdec_stop(sdec_dev);
            if(enable)
            {
			    g_dcii_subt_enable = TRUE;
				g_subt_enable = TRUE;
				#ifdef DUAL_ENABLE
               
                atsc_subt_unreg_all_dmx();
				subt_Serv.device = sdec_dev;
				subt_Serv.request_write = (Request_write)atsc_sdec_m3327_request_write;
				subt_Serv.update_write = (Update_write)atsc_sdec_m3327_update_write;
				subt_Serv.service_pid = g_current_pid;
				subt_Serv.str_type = DC2SUB_STR;
				reg_code = dmx_register_service(dmx_dev,6,&subt_Serv);
				if(reg_code == RET_SUCCESS)
				{
					atsc_subt_dmx_used[dmx_index] = 1;
					LIBSUBT_PRINTF("%s : subt success to start dmx[%d]!\n",__FUNCTION__,__LINE__,dmx_index);
				}
				else
				{
					LIBSUBT_PRINTF("%s :line %d: Error: subt fail to start dmx[%d]!\n",__FUNCTION__,__LINE__,dmx_index);
				}
		   		LIBSUBT_PRINTF("%s-lib_subt_atsc_create_task()\n",__FUNCTION__);	
		   		lib_subt_atsc_section_parse_create_task();//need remote call
                lib_subt_atsc_create_task();
				#endif

				#ifndef DUAL_ENABLE
                lib_subt_atsc_start_filter(dmx_index,g_current_pid);
		   		LIBSUBT_PRINTF("%s-lib_subt_atsc_create_task()\n",__FUNCTION__);							
                lib_subt_atsc_create_task();
                #endif
            }
            else
            {
                g_dcii_subt_enable = FALSE;
				g_subt_enable = FALSE;
				
                #ifdef DUAL_ENABLE
				atsc_subt_unreg_all_dmx();
				LIBSUBT_PRINTF("%s-sdec_stop() -Line(%d)\n",__FUNCTION__,__LINE__); 		
				g_current_pid = 0x1fff;
                lib_subt_atsc_clean_up();
                lib_subt_atsc_delete_timer();
	      		LIBSUBT_PRINTF("%s-lib_subt_atsc_terminate_task()\n",__FUNCTION__);			            				
                lib_subt_atsc_terminate_task();
				lib_subt_atsc_section_parse_terminate_task();
				#endif

				#ifndef DUAL_ENABLE
                lib_subt_atsc_stop_filter(dmx_index);
                lib_subt_atsc_clean_up();
                lib_subt_atsc_delete_timer();
	      		LIBSUBT_PRINTF("%s-lib_subt_atsc_terminate_task()\n",__FUNCTION__);			            				
                lib_subt_atsc_terminate_task();
                #endif
            }
            return SUCCESS;
        }
        if(g_subt_lang_num>0 && g_current_pid == 0x1fff)
        { 
			#ifdef DUAL_ENABLE
            atsc_subt_unreg_all_dmx();
            lib_subt_atsc_clean_up();
            lib_subt_atsc_delete_timer();
			#endif

			#ifndef DUAL_ENABLE
            lib_subt_atsc_stop_filter(dmx_index);
            lib_subt_atsc_clean_up();
            lib_subt_atsc_delete_timer();
            #endif
        }
        return SUCCESS;
    }
#endif
	if(enable == TRUE)
	{
		if(g_subt_lang_num>0 && g_current_pid != 0x1fff)
		{
			subt_unreg_all_dmx();
			subt_Serv.device = sdec_dev;
			subt_Serv.request_write = (Request_write)sdec_request_write;
			subt_Serv.update_write = (Update_write)sdec_update_write;
			subt_Serv.service_pid = g_current_pid;
		
			reg_code = dmx_register_service(dmx_dev,4,&subt_Serv);
			if(reg_code == RET_SUCCESS)
			{
				subt_dmx_used[dmx_index] = 1;
				LIBSUBT_PRINTF("%s : subt success to start dmx[%d]!\n",__FUNCTION__,dmx_index);
			}
			else
			{
				LIBSUBT_PRINTF("%s : Error: subt fail to start dmx[%d]!\n",__FUNCTION__,dmx_index);
			}
			LIBSUBT_PRINTF("%s-sdec_start()\n",__FUNCTION__);			
			sdec_start(sdec_dev,g_subt_lang[g_current_lang].com_page,g_subt_lang[g_current_lang].anci_page);
		}
		g_subt_enable = TRUE;
	}
	else
	{
		subt_unreg_all_dmx();
	    	LIBSUBT_PRINTF("%s-sdec_stop() -Line(%d)\n",__FUNCTION__,__LINE__);			
		sdec_stop(sdec_dev);
		g_current_pid = 0x1fff;
		g_subt_enable = FALSE;
	}
	return SUCCESS;
}

void subt_pvr_set_language(struct t_subt_lang* list ,UINT8 num)
{
	UINT8 i = 0;
	int nSize = sizeof(struct t_subt_lang);
	g_subt_lang_num = num;
	LIBSUBT_PRINTF("%s : num[%d]!\n",__FUNCTION__,num);
	for(i=0; i<num; i++)
	{
		MEMCPY(&(g_subt_lang[i]),&(list[i]),nSize);
	}
}

INT32 subt_pvr_enable(BOOL enable,UINT16 dmx_id)
{
	struct register_service subt_Serv;
	static struct sdec_device *sdec_dev;
	struct dmx_device *dmx_dev = NULL;
    RET_CODE reg_code = RET_SUCCESS;
	sdec_dev = (struct sdec_device *)dev_get_by_name("SDEC_M3327_0");
	dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, dmx_id);
	LIBSUBT_PRINTF("%s : PVR subt Enable[%d] DMX[%d]!\n",__FUNCTION__,enable,dmx_id);
	if(enable == TRUE)
	{
		dmx_index = dmx_id;
		if(g_subt_lang_num>0 && g_current_pid != 0x1fff)
		{
			dmx_unregister_service(dmx_dev,4);
			subt_Serv.device = sdec_dev;
			subt_Serv.request_write = (Request_write)sdec_request_write;
			subt_Serv.update_write = (Update_write)sdec_update_write;
			subt_Serv.service_pid = g_current_pid;
            reg_code=dmx_register_service(dmx_dev,4,&subt_Serv);
            if(reg_code == RET_SUCCESS)
            {
                subt_dmx_used[dmx_index] = 1;
				LIBSUBT_PRINTF("%s : subt success to start dmx[%d]!\n",__FUNCTION__,dmx_index);
            }
			else
			{
				LIBSUBT_PRINTF("%s : Error: subt fail to start dmx[%d]!\n",__FUNCTION__,dmx_index);
			}
			sdec_start(sdec_dev,g_subt_lang[g_current_lang].com_page,g_subt_lang[g_current_lang].anci_page);
		}
		g_pvrsubt_enable = TRUE;
	}
	else
	{
		if(g_pvrsubt_enable)
			dmx_index = 0;
		dmx_unregister_service(dmx_dev,4);
		sdec_stop(sdec_dev);
		g_current_pid = 0x1fff;
		g_pvrsubt_enable = FALSE;
		g_subt_lang_num = 0;
#ifdef LIB_TSI3_FULL
		MEMSET(prev_subt, 0, sizeof(prev_subt));
		subt_descriptor_reset();
#endif
		
	}
	return SUCCESS;
}

BOOL subt_check_enable()
{
	return g_subt_enable;
}
BOOL dcii_subt_check_enable()
{
    return g_dcii_subt_enable;
}

void subt_reg_callback(SUBT_EVENT_CALLBACK callback)
{
	osal_task_dispatch_off();
	subt_event_callback = callback;
	osal_task_dispatch_on();
}

void subt_unreg_callback()
{
	osal_task_dispatch_off();
	subt_event_callback = NULL;
	osal_task_dispatch_on();
}
#endif
